package com.securityLearn.securityAuth.config.security;

import com.alibaba.fastjson.JSONObject;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

import java.io.PrintWriter;

/**
 * security 安全配置
 * @EnableWebSecurity 1. 启用Security的配置
 *
 * @author duzq
 * @date 2021-8-30 13:49:36
 */
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 2. 定义用户信息查询服务
     *
     * 配置成数据库，查看
     *    com.securityLearn.securityAuth.config.security.UserDetailsServiceImpl
     * @return

    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        // 声明一些固定的用户，后续改造成数据库查询
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("zhangsan").password("123").authorities("p1").build());
        manager.createUser(User.withUsername("lisi").password("456").authorities("p2").build());
        return manager;
    }*/

    /**
     * 3. 声明密码编码器
     *
     * 加密比较
     * return new BCryptPasswordEncoder();
     *
     * 明文比较
     * return NoOpPasswordEncoder.getInstance();
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    /**
     * 4. 安全拦截机制
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 访问 /r/r1 必须拥有 p1 权限
                .antMatchers("/r/r1").hasAnyAuthority("p1")
                // 访问 /r/r2 必须拥有 p2 权限
                .antMatchers("/r/r2").hasAnyAuthority("p2")
                // 【/r/**】规则下的请求，必须认证通过
                // 【 PS: 范围较大的配置，必须放在范围较小的配置后面，否则较小的配置不生效！ 】
                .antMatchers("/r/**").authenticated()
                // 除了【/r/**】以外的规则，可以直接访问
                .anyRequest().permitAll()
                .and()
                // 允许表单登录，登录成功跳转到指定地址 （ 不配置自定义登录页，使用 Security 默认登录功能及页面 ）
                .formLogin()
                // 自定义登录页面
                .loginPage("/myLogin")
                // 验证账户信息的方法
                .loginProcessingUrl("/login")
                // 认证成功后的自定义处理类
                .successHandler((request, response, authentication) -> {
                    System.out.println("successHandler(认证成功后的自定义处理方法)");
                    System.out.println("successForwardUrl(认证成功后跳转的url)");
                    System.out.println("以上二选一，谁先声明，谁启作用！");
                })
                // 认证成功后的跳转页面
                .successForwardUrl("/login-success")
                // 认证失败后，的自定义处理类
                .failureHandler((request, response, exception) -> {
                    // 输出JSON返回结果
                    JSONObject resJson = new JSONObject();
                    resJson.put("status", 0);
                    resJson.put("msg", exception.getMessage());

                    response.setCharacterEncoding("utf-8");
                    response.setContentType("application/json; charset=utf-8");
                    PrintWriter writer = response.getWriter();
                    writer.write(resJson.toJSONString());
                })
                .and()
                // 退出登录配置
                .logout()
                // 退出登录使用的URL
                .logoutUrl("/logout")
                // 退出成功后跳转的URL
                .logoutSuccessUrl("/login-view?logout")
                // 退出成功后的自定义处理方法
                .logoutSuccessHandler((request, response, authentication) -> {
                    System.out.println("logoutSuccessHandler(退出成功后的自定义处理方法)");
                    System.out.println("logoutSuccessUrl(退出成功后跳转的url)");
                    System.out.println("以上二选一，谁先声明，谁启作用！");
                })
                // 允许任意用户访问基于表单登录的所有的URL
                .permitAll();
        // 禁用csrf安全认证
        http.csrf().disable();
    }
}
